//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//
// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
//
// Module Name:
//
//    Impl.c   
//
// Abstract:
//
//    Driver entry points for Littleton SDIO driver 
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <Littleton.h>
#include <SD.h>
#include "xllp_gpio_plat.h"
#include "Args.h"
#include "ioctl_cfg.h"
#include <xllp_defs.h>
#include <xllp_gpio.h>
#include <xllp_mfp.h>
#include <xllp_bcr.h>
#include "monahans.h"
#include "monahans_base_regs.h"
#include "GPX_Driver.h"
#include "GPX_XLLP.h"

#define ZONE_ERROR 1

typedef struct _SDHCCardDetect{
    PSDH_HARDWARE_CONTEXT pHardwareContext;

    //load when inited
    P_XLLP_GPIO_T gpio_reg;
    
    //board related
    XLLP_UINT32_T CDGpioID;
    XLLP_UINT32_T WPGpioID;

    //dynamic status    
    BOOL fSimulateCardInsertion;
    //BOOL initing;    

    volatile int *  m_MFPBase;
    volatile int *  m_I2CBase;
    volatile int *  m_OSTBase;
    volatile int *    m_GPIOBase;

    HANDLE hCardInsertInterruptEvent;
    HANDLE hCardInsertInterruptThread;
}SDHCCardDetect, *PSDHCCardDetect;

void  ProcessCardInsertion(void *pContext);
void  ProcessCardRemoval(void *pContext);
BOOL  DriverShutdown(void *pContext);

DWORD SDCardDetectIstThread(void *pContext);

static XLLP_UINT32_T CDGpioID[3]={0, 0, 0};
static XLLP_UINT32_T WPGpioID[3]={0, 0, 0};
static DWORD  m_MMC1CDIrqID;

//This function inited GPIO...
BOOL InitializeHardware(PSDH_HARDWARE_CONTEXT pHardwareContext)
{
    PSDHCCardDetect pCardDetect;
    int index=pHardwareContext->dwSDHCIndex -1;

    //init CardDetect structure
    if(!(pCardDetect= (PSDHCCardDetect)malloc( sizeof(SDHCCardDetect) ))){
        DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("[%s]Card Detect alloc memory failed\r\n"), pHardwareContext->szName));
        return FALSE;
    }
    memset( pCardDetect, 0, sizeof(SDHCCardDetect) );    
    pHardwareContext->pCardDetect=pCardDetect;
    pCardDetect=(PSDHCCardDetect)pHardwareContext->pCardDetect;

    pCardDetect->pHardwareContext = pHardwareContext;

    //init platform
    pCardDetect->CDGpioID=CDGpioID[index];
    pCardDetect->WPGpioID=WPGpioID[index];
    
    if(FALSE==pHardwareContext->hotRemovable){
        RETAILMSG(1, (TEXT("[MMC%d] the sdhc is not hot removable/r/n"), index+1));
        return TRUE;
    }
#if 0        
    GPX_SetDirection(pCardDetect->CDGpioID, XLLP_GPIO_DIRECTION_IN);
    GPX_SetDirection(pCardDetect->CDGpioID, XLLP_GPIO_DIRECTION_IN);
#endif

    RETAILMSG(1, (TEXT("[%s] Card Detect Platform initializition has been done/r/n"), pHardwareContext->szName));
    return TRUE;
}

void UnInitializeHardware(PSDH_HARDWARE_CONTEXT pHardwareContext)
{
    PSDHCCardDetect pCardDetect= (PSDHCCardDetect)(pHardwareContext->pCardDetect);

    /*if(NULL!=pCardDetect->gpio_reg){
        MmUnmapIoSpace((PVOID)pCardDetect->gpio_reg, sizeof(XLLP_GPIO_T));  
    }*/
    if(NULL != pCardDetect){
        free(pCardDetect);
    }
}

//Currently we don't use MMC1 socket now
BOOL IsCardWriteProtected(PSDH_HARDWARE_CONTEXT pHardwareContext)
{
    PSDHCCardDetect pCardDetect= (PSDHCCardDetect)(pHardwareContext->pCardDetect);
    XLLP_STATUS_T status;
    XLLP_LEVEL_T level;
    
    if(FALSE==pHardwareContext->hotRemovable){
        return TRUE;
    }

    if (pCardDetect->WPGpioID)
        status = XllpGpioGetLevel((P_XLLP_GPIO_T)pCardDetect->m_GPIOBase, pCardDetect->WPGpioID, &level);
    else
        level = XLLP_LO;

    RETAILMSG(1, (TEXT("[SDHC%d] Card WP=%d,%d\r\n"), pHardwareContext->szName, level)); 
    return ((level == XLLP_HI) ? XLLP_TRUE : XLLP_FALSE);
}

BOOL IsCardPresent(PSDH_HARDWARE_CONTEXT pHardwareContext)
{
    PSDHCCardDetect pCardDetect= (PSDHCCardDetect)(pHardwareContext->pCardDetect);
    XLLP_STATUS_T status;
    XLLP_LEVEL_T level=XLLP_HI;
    
    if(FALSE==pHardwareContext->hotRemovable){
        return TRUE;
    }

    status = XllpGpioGetLevel((P_XLLP_GPIO_T)pHardwareContext->pGPIORegisters, pCardDetect->CDGpioID, &level);
    RETAILMSG(1, (TEXT("[%s] Card Detect level = %d (Low= present)\r\n"), pHardwareContext->szName, level)); 
    return ((level == XLLP_HI) ? XLLP_FALSE : XLLP_TRUE);
}

void MMCPowerControl(void *pContext, BOOL fPowerOn )
{
//current not support 
}

//set when resume after suspend
void SimulateCardInsertion(PSDH_HARDWARE_CONTEXT pController)
{
    PSDHCCardDetect pCardDetect= (PSDHCCardDetect)(pController->pCardDetect);

    pCardDetect->fSimulateCardInsertion = TRUE;
    SetEvent( pCardDetect->hCardInsertInterruptEvent );
}

///////////////////////////////////////////////////////////////////////////////
//  SDCardDetectIstThread - IST thread for card detect interrupts
//  Input:  pContext - pointer to the device context
//  Output: 
//  Return: thread exit code
///////////////////////////////////////////////////////////////////////////////
DWORD SDCardDetectIstThread(void *pContext)
{
    DWORD dwTimeout = INFINITE;
    DWORD waitStatus;
    PSDH_HARDWARE_CONTEXT pHardwareContext=(PSDH_HARDWARE_CONTEXT)pContext;
    PSDHCCardDetect pCardDetect=(PSDHCCardDetect)(pHardwareContext->pCardDetect);

    //set thread priority
    if (!CeSetThreadPriority(GetCurrentThread(), pHardwareContext->dwCardDetectIstThreadPriority)) {
           DbgPrintZo(SDCARD_ZONE_WARN,
               (TEXT("SDCardDetectIstThread: warning, failed to set CEThreadPriority \n")));
        }

    //when detect it at 1st time, judge if it is inserted 
    //if(TRUE==pCardDetect->initing){ 
    if( IsCardPresent(pContext) ){
              RETAILMSG(1, (TEXT("[%s] Card inserted!\r\n"), pHardwareContext->szName));     
            ProcessCardInsertion(pContext);
    }
        //    pCardDetect->initing = FALSE;
    //}

    /*about not hotRemovable: --------------------/
    /---will detect when init and resume after suspend */
    while(TRUE){
        //wait for events: insert or removed
        waitStatus= WaitForSingleObject( pCardDetect->hCardInsertInterruptEvent,  dwTimeout);    
        if (WAIT_OBJECT_0 != waitStatus) {
            RETAILMSG(1, (TEXT("[%s] SDCardDetectIstThread: Wait Failed! 0x%08X \n"), pHardwareContext->szName, waitStatus));
            return 0;
        }
        //driver shut down
        if( DriverShutdown(pContext) ) {
            RETAILMSG(1, (TEXT("[%s] SDCardDetectIstThread: Thread Exiting\r\n"), pHardwareContext->szName));
            return 0;
        }

        //if is suspend from remove, 1st clean up card, then do card insert or remove
        if( pCardDetect->fSimulateCardInsertion){
            pCardDetect->fSimulateCardInsertion = FALSE;
            ProcessCardRemoval(pContext);
            RETAILMSG(1, (TEXT("[%s] fSimulateCardInsertion\r\n"), pHardwareContext->szName));
        }
       

        // bman:  test here for fix
        {
            /*int stop_0, stop_4, diff_0, diff_4;
            int start_0 = pOST->oscr0;
            int start_4 = pOST->oscr4;

            RETAILMSG(1, (TEXT("+MMCBMAN: 0x%x, 0x%x, %d\r\n"), start_0, start_4, GetTickCount()));*/

            Sleep( 100 ); // delay to handle bouncing effect on the interrupt line

            /*stop_0 = pOST->oscr0;
            stop_4 = pOST->oscr4;
            diff_0 = (stop_0 - start_0);
            diff_4 = (stop_4 - start_4);
            RETAILMSG(1, (TEXT("-MMCBMAN: 0x%x, 0x%x, %d, %d, %d\r\n"), stop_0, stop_4, diff_0, diff_4, GetTickCount()));*/
        }
        //process events: card insert and remove
        if( IsCardPresent(pContext) ){
            ProcessCardInsertion(pContext);
        }else {
            ProcessCardRemoval(pContext);
        }

    } // while
    
    return TRUE;
}

//#define getGPXVerg(x) ((0==x)?((BYTE) -1 ):( (BYTE)x-128))

BOOL  SetupCardDetectIST( void *pController )
{
    DWORD threadID;                         // thread ID
    PSDH_HARDWARE_CONTEXT pHardwareContext= (PSDH_HARDWARE_CONTEXT)pController;
    PSDHCCardDetect pCardDetect=(PSDHCCardDetect)(pHardwareContext->pCardDetect);        

//    XLLP_BOOL_T blresult;
    DWORD m_dwSysIntr;
    BOOL bSuccess;

    //if sdhc is not hot removable, fake a intr
    if(FALSE==pHardwareContext->hotRemovable){
        pCardDetect->hCardInsertInterruptEvent = CreateEvent(NULL, FALSE, FALSE,TEXT("UnPNP_MMC_CD_EVENT"));
        goto startThread;
    }

    RETAILMSG(1, (_T("MMC1 CD Calling InterruptInitialize MFP base = %8x, offset=%x \r\n"),pHardwareContext->pMFPRegisters, XLLP_MFP_PIN_GPIO15_OFFSET));
//    XllpMfpSetAfDs ((P_XLLP_VUINT32_T) pHardwareContext->pMFPRegisters,XLLP_MFP_PIN_GPIO15_OFFSET, XLLP_MFP_ALT_FN_0, XLLP_MFP_DS_04X);
//    XllpMfpConfigurePullUpDown((P_XLLP_VUINT32_T)pCardDetect->m_MFPBase, XLLP_MFP_PIN_GPIO15_OFFSET, XLLP_MFP_PULL_UP);
//    XllpGpioSetDirection((P_XLLP_GPIO_T)pCardDetect->m_GPIOBase, 15, XLLP_GPIO_DIRECTION_IN);
    XllpGpioSetFallingEdgeDetectEnable((P_XLLP_GPIO_T) pHardwareContext->pGPIORegisters, 15,  XLLP_ON);
    XllpGpioSetRisingEdgeDetectEnable((P_XLLP_GPIO_T) pHardwareContext->pGPIORegisters, 15, XLLP_ON);

    pCardDetect->hCardInsertInterruptEvent = CreateEvent(0, FALSE, FALSE, NULL);
    if (pCardDetect->hCardInsertInterruptEvent == NULL) 
    {
        DWORD ret = GetLastError();
        RETAILMSG(1, (_T("%s Error creating MMC1 Card Detect interrupt event. Error = %d\r\n"),  "MMC1", ret));
        return ERROR_INVALID_DATA;
    }

    // GPIO15, MMC1_CD_N
    m_MMC1CDIrqID=IRQ_GPIO_SHARE(15);
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_MMC1CDIrqID, sizeof(DWORD), &(m_dwSysIntr), sizeof(DWORD), NULL))
    {
        // invalid SDIO SYSINTR value!
        DEBUGMSG(ZONE_ERROR, (TEXT("Error obtaining PowerIC SYSINTR value!\n")));
        m_dwSysIntr = SYSINTR_UNDEFINED;
        return ERROR_INVALID_DATA;
    }

    RETAILMSG(1, (_T("MMC1 CD Calling InterruptInitialize...m_MMC1CDIrqID = %d, m_dwSysIntr=%d \r\n"),m_MMC1CDIrqID, m_dwSysIntr));
    
    bSuccess=InterruptInitialize(m_dwSysIntr,pCardDetect->hCardInsertInterruptEvent,0,0);
    if (!bSuccess)  DEBUGMSG(1, (_T("InterruptInitialize failed \r\n")));

startThread:;

        // create the interrupt thread to handle card insertion events
    pCardDetect->hCardInsertInterruptThread = 
                    CreateThread(NULL,
                                 0,
                                 (LPTHREAD_START_ROUTINE)SDCardDetectIstThread,
                                 pHardwareContext,
                                 0,
                                 &threadID);
    
    if (NULL == pCardDetect->hCardInsertInterruptThread) {
        RETAILMSG(1, (TEXT("[%s] SetupCardDetectIST() failed - \n"),pHardwareContext->szName)); 
        return FALSE;
    }

    RETAILMSG(1, (TEXT("[%s] SetupCardDetectIST() successfully \n"),pHardwareContext->szName)); 
    return TRUE;
}

void CleanupCardDetectIST(PSDH_HARDWARE_CONTEXT pController)
{
//    HANDLE hOpenContentGPX;
//    XLLP_BOOL_T blresult;
    PSDHCCardDetect pCardDetect=(PSDHCCardDetect)(pController->pCardDetect);
//    BYTE vreg = getGPXVerg(pCardDetect->CDGpioID);

    //if sdhc is not hot removable, something do not need to clean
    if(FALSE==pController->hotRemovable){
        goto endThread;
    }
#if 0
    // clean up GPX envents
    hOpenContentGPX = GPX_OPEN();
    //GPX_DEBUG_PARAM_CHECK(INVALID_HANDLE_VALUE!=hOpenContentGPX);
    GPX_DISABLE_EVENT(hOpenContentGPX, vreg, blresult);
    //GPX_DEBUG_PARAM_CHECK(blresult);
    GPX_CLOSE(hOpenContentGPX);
#endif

endThread:;

        // clean up card insertion IST 
    if (NULL != pCardDetect->hCardInsertInterruptThread) {
        // wake up the IST
            SetEvent(pCardDetect->hCardInsertInterruptEvent);
        // wait for the thread to exit
            WaitForSingleObject(pCardDetect->hCardInsertInterruptThread, INFINITE); 
            CloseHandle(pCardDetect->hCardInsertInterruptThread);
            pCardDetect->hCardInsertInterruptThread = NULL;
    }

    RETAILMSG(1, (TEXT("[%s] CleanupCardDetectIST()  \n"),pController->szName)); 
    
}


void WLAN_PowerOn(PSDH_HARDWARE_CONTEXT pController)
{
    XLLP_STATUS_T status;
    BSP_ARGS args;
    DWORD size;
    BOOL bRet = FALSE;

    if (KernelIoControl(IOCTL_GET_BSP_ARGS, NULL, 0, &args, sizeof(args), &size))
    {
        RETAILMSG(1, (TEXT("[SDHC: WLAN] WLAN_PowerOn args.TechBoardUsage = 0x%x!\r\n"), args.TechBoardUsage));

        if ((args.TechBoardUsage == BSP_ARGS_TECHBOARD_BT_WLAN) || (args.TechBoardUsage == BSP_ARGS_TECHBOARD_WLAN))
        {
            //DbgPrintfW(TEXT("[SDHC1: WLAN] WiFi will be enable\r\n"));                    
        }
        else
        {
            RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN_PowerOn: WiFi is not enable\r\n")));        
            return;
        }
    }

   status=GPX_SetOutputLevel(XLLP_GPIO_WIFI_PDN, XLLP_LO);
   if(XLLP_STATUS_SUCCESS!=status)
        goto rstErr;

   status=GPX_SetOutputLevel(XLLP_GPIO_WIFI_RST, XLLP_HI);
   if(XLLP_STATUS_SUCCESS!=status)
        goto rstErr;

   status=GPX_SetOutputLevel(XLLP_GPIO_WIFI_RST, XLLP_LO);
   if(XLLP_STATUS_SUCCESS!=status)
        goto rstErr;

   Sleep(1);//wait 1 ms

   status=GPX_SetOutputLevel(XLLP_GPIO_WIFI_RST, XLLP_HI);
   if(XLLP_STATUS_SUCCESS!=status)
        goto rstErr;

    bRet = TRUE;
        
rstErr:
    if (bRet)
    {
        RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN power on successfully \r\n")));
    }
    else
    {
        RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN power on failed\r\n")));
    }
    
    return;

}




void WLAN_PowerOff(PSDH_HARDWARE_CONTEXT pController)
{
    XLLP_STATUS_T status;
    BSP_ARGS args;
    DWORD size;
    BOOL bRet = FALSE;
    
    if (KernelIoControl(IOCTL_GET_BSP_ARGS, NULL, 0, &args, sizeof(args), &size))
    {
        RETAILMSG(1, (TEXT("[SDHC: WLAN] WLAN_PowerOff args.TechBoardUsage = 0x%x!\r\n"), args.TechBoardUsage));

        if ((args.TechBoardUsage & BSP_ARGS_TECHBOARD_BT_WLAN) || (args.TechBoardUsage & BSP_ARGS_TECHBOARD_WLAN))
        {
            //DbgPrintfW(TEXT("[SDHC1: WLAN] WiFi will be enable\r\n"));                    
        }
        else
        {
            RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN_PowerOff: WiFi is not enable\r\n")));
            return;
        }
       }

   status=GPX_SetOutputLevel(XLLP_GPIO_WIFI_PDN, XLLP_HI);
   if(XLLP_STATUS_SUCCESS!=status)
        goto rstErr;

    bRet = TRUE;
    
rstErr:
    if (bRet)
    {
        RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN power off successfully \r\n")));
    }
    else
    {
        RETAILMSG(1,(TEXT("[SDHC: WLAN] WLAN power off failed\r\n")));
    }

    return;
}

//this function only called when suspend-resume
void MMCSlotPowerSet(PSDH_HARDWARE_CONTEXT pHc, BOOL on)
{
/*   will add code for Littleton */    
    return;
}
